/********************************************************************
	created:	1/11/2005   2:20
	filename: 	BezierCamera.cpp
	author:		GMKal (exile79@gmail.com)
	
	purpose:	a camera class that flies from point to point following bezier 
				curves both for its position and view vectors

    last modified:  1/11/2005   2:20
*********************************************************************/



#include "StdAfx.h"
#include ".\beziercamera.h"

BezierCamera::BezierCamera(void)
:	m_timeElapsed(0.0),
	m_destDT(0.0)
{
}

BezierCamera::~BezierCamera(void)
{
}


/*
 *	calling this means: 
 *	after desiredDT seconds the position of the camera must be (px,py,pz)
 *	and must look at (vx,vy,vz)
 */
void BezierCamera::MoveTo(float px,float py,float pz, float vx,float vy,float vz,
						  double desiredDT)
{
	m_targetPosition.Set(px,py,pz);
	m_targetView.Set(vx,vy,vz);

	m_timeElapsed=0.0;
	m_destDT=desiredDT;
	
	//
	// find two appropriate control points for the curve
	Vector3 dv1((m_targetPosition-mPosition)/3.f);
	Vector3 dv2((m_targetView-mView)/3.f);
	Vector3 dv3((mView-mPosition).Normalized());
	Vector3 dv4((m_targetView-m_targetPosition).Normalized());
	

	//
	// first the position path
	float len = dv1.Length();
	Vector3 pc1(mPosition+dv1-dv3*len);
	Vector3 pc2(m_targetPosition-dv1-dv4*len);
	m_positionPath.Set(this->mPosition,pc1,pc2,m_targetPosition);

	//
	// then, the view path
	/*pc1 = mView+dv2+dv3;
	pc2 = m_targetView-dv2+dv4;*/
	pc1 = mView+dv2;
	pc2 = m_targetView-dv2;
	m_viewPath.Set(mView,pc1,pc2,m_targetView);
}


void BezierCamera::MoveTo(const Vector3& np,const Vector3& nv,
						  double desiredDT)
{
	MoveTo(np.x,np.y,np.z,nv.x,nv.y,nv.z,desiredDT);
}

/*
 *	update the position of the camera according to the passed time
 */
bool BezierCamera::Update(double dt)
{
	if(dt<=0.0)
		return false;
	if(m_timeElapsed>=m_destDT) 
		return true;
	
	m_timeElapsed += dt;	// advance elapsed time
	
	//
	// if the desired time is exhausted, set camera to target points and return
	if(m_timeElapsed>=m_destDT)	
	{
		SetPosition(m_targetPosition);
		SetView(m_targetView);
		return true;
	}

	//
	// we are still before the desired time, so interpolate between points
	float factor = float(m_timeElapsed/m_destDT);
	
	Vector3 vec = m_positionPath.PointOnCurve(factor);
	mPosition=vec;

	vec = m_viewPath.PointOnCurve(factor);
	mView = vec;

	return false;	// not reached target yet
}